home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-10-23 | 49.7 KB | 1,578 lines |
- % Version 1.3 makes it easier to create other changes files (6/89)
- \font\twelvept=cmbx12
- \font\tentex=cmr10
- \def\topofcontents{\null\vfill\eject
- \def\titlepage{T}
- \centerline{{\twelvept The \TeX IX Index Program}}
- \centerline{{\twelvept For IBM VM/CMS Pascal/VS}}
- \vskip15pt
- \centerline{Version 1.3, June 1989}
- \hbox{\vbox{\hsize\the\hsize This work is
- protected as an unpublished work under U.S. copyright laws.
- Copyright $\copyright$ 1988 by WSUCSC. All rights Reserved.}}
- \vskip18pt
- \hbox{\vbox{\hsize\the\hsize This software is furnished under a
- license for
- use only on a single computer system and may be copied only
- with the inclusion of the above copyright notice.
- This software, or any other copies
- thereof, may not be provided or otherwise made available to any
- other person except for use on such system and to one who agrees to
- these license terms. Title to and ownership of the software shall
- at all times remain in WSUCSC.}}
- \vfill}
- \let\tentex=\tt
- \def\_{\leavevmode \kern.06em \vbox{\hrule width.3em}}%
- %
- \def\}{\ifmmode \rbrace
- \else $\rbrace$\fi}%
- %
- \def\{{\ifmmode \lbrace
- \else $\lbrace$\fi}%
- %
- \def\us#1{$\underline{\smash{\hbox{#1}}}$}%
- \def\lin#1{\par
- \leftskip 0pt
- \advance \leftskip by #1
- }%
- \def\vs#1{\vskip #1\relax}
- \catcode`*=11
- % labeled definition macro
- %
- \newdimen\la*w \la*w=1in % Label width
- \newtoks\la*g \la*g={1em} % Label gutter
- \newtoks\la*s \la*s={12pt} % Skip before label
- \newtoks\la*f \la*f={\rm} % Label font
- \newbox\tempbox
- %
- \long\def\label#1{\par\vskip\the\la*s
- \setbox\tempbox=\vtop{\hsize=\la*w
- \leftskip=0pt
- \rightskip=0pt plus2em
- \tolerance=1600
- \noindent
- \the\la*f
- #1}%
- \hangindent=\la*w
- \advance \hangindent by \the\la*g
- \hangafter=1
- \noindent
- \setbox0=\hbox{\rlap{\box\tempbox}}\ht0=0pt\dp0=0pt\box0%
- \hskip\la*w
- \hskip\the\la*g
- \ignorespaces}
- \let\la=\label
- \catcode`*=12
- \let\nin=\noindent
- \def\lbr{\null\hfil\break}
- \def\PASCAL{{\sc PASCAL/VS}}
- \def\hs#1{\hskip#1}
- \def\text#1{{\it \TeX T#1}}
- \def\9{\it}
- \def\bs{$\backslash$}
- % Version 1.0; Dean Guenther; 4/1/86
- %
- @* Introduction.
- This procedure was created to give \text1\ the ability to produce a sorted
- index in the same one pass, instead of creating the index, sorting it, and
- printing the index out in three separate steps.
-
- To accomplish this feat, a new control sequence, \bs{}sortindex, was added to
- the basic \TeX\ program which gives the \text1\ user up to three sorted
- index files per run. The format of this new control sequence is
- \par{\tt\indent\bs{}sortindex\it n}
- \par
- \nin where {\it n} is the index file number: 1, 2, or 3.
-
- @ The @^TEXIX@>
- program is written entirely in WEB, except for an external
- procedure, {\it plsort}, which is written in @^PL/1@> PL/1.
- This was necessary since
- \PASCAL\ cannot call
- @:plsort@>
- Syncsort @^SYNCSORT@>
- to do an internal sort, and PL/1 can.
-
- @
- Also, it should be pointed out early that I made use of \PASCAL'
- nifty string handling capability, in particular, the |string|,
- |index| and |substr| functions. If needed, these should not be too
- difficult to translate into another \PASCAL\
- compiler (famous last words).
-
- @p
- segment texix;
- procedure texix(ix:char); external;
- procedure texix;
- const @<Global Constants@>
- type @<Global Types@>
- var @! m,k,i,j :integer;@/
- @<Global Variables@>
-
- @ The file {\it ix\_file}
- is the file opened for output in the \text1\ session
- itself. It will be closed in TEXIX, opened for input, closed again, and
- finally opened for output where the final sorted index file will be
- written to, complete with all \text1\ markup necessary for printing
- the index.
-
- @<Global Var...@>=
- sysprint:text;
- @!ix_file :text;
-
- @ The {\it sort\_file} is used for the internal sort only. The \text1\ user
- never has access to it.
-
- @<Global Var...@>=
- @!sort_file :file of sort_type;
-
- @* Macros and definitions.
- Here are some macros and definitions used throughout.
-
- @d incr(#) == # := # + 1
- @d decr(#) == # := # - 1
-
- @d othercases == otherwise
- @d endcases == end;
-
- @d dosubstr == substr
- @d doindex == index
-
- @f othercases == else
- @f endcases == end
-
- @d getout == return
- @d messages == sysprint
-
- @d max_field = 300
- @d max_levels = 3
- @d max_lrecl = 2048
-
- @d remove_characters(#) == if length(in_record) > # then
- in_record := dosubstr(in_record,1 + #)
- else in_record := ''
-
- @d do_nothing == begin end
-
- @d do_sort_as == begin remove_characters(6);
- i := doindex(in_record,'{$}');
- write_sort_chars(i-1);
- remove_characters(3);
- end
-
- @d check_case == begin
- if not respect_case then for j:= 1 to
- sort_part[i].field_lngth do sort_part[i].field_level[j] :=
- upper_case(sort_part[i].field_level[j]); end
-
- @d string_type(#) == string(#)
-
- @d ccat_temp == @t\hs{2em}@>@=||@>@t\hs{2em}@>
-
-
- @d add_comma(#) == # := ccat(#,',')
- @d add_cmma_blnk(#) == # := ccat(#,', ')
-
- @d do_when_bold == begin
- if length(bold_string) > 0 then add_comma(bold_string);
- bold_string:=
- ccat(ccat(ccat(bold_string,'{\bd '),curr_str_page),'}');
- @.\bs{}bd@>
- end
-
- @d do_when_underscore == begin
- if length(us_string) > 0 then add_comma(us_string);
- us_string:=
- ccat(ccat(ccat(us_string,'\us{'),curr_str_page),'}');
- @.\bs{}us@>
- end
-
- @d do_when_italic == begin
- if length(rm_string) > 0 then add_comma(rm_string);
- rm_string:=
- ccat(ccat(ccat(rm_string,'{\it '),curr_str_page),'}');
- @.\bs{}it@>
- end
-
- @d do_when_roman == begin
- if length(rm_string) > 0 then add_comma(rm_string);
- rm_string:=ccat(rm_string,curr_str_page);
- end
-
- @d do_write(#)==write(#)
-
- @d do_lnwrite(#)==writeln(#)
-
- @ This is arbitrary, but
- there should never be more than 8 indicies.
-
- @d s_file_number == '9'
-
- @ This is used to print the subentry1 header if there are no page
- numbers under its subentry and there are under subentry2.
-
- @d id2_missing_check==
- curr_level:=2;
- if sort_record.sort_part[3].field_lngth=0
- then do_nothing else begin
- id2_is_missing:=true;
- write_header(sort_record.print[2].field_lngth,
- sort_record.print[2].field_level);
- id2_is_missing:=false;
- curr_level:=3;end
-
- @ This is used to print the primary header if there are no page
- numbers under the primary header, and there are page numbers under
- either subentry1 or subentry2.
-
- @d id1_missing_check==if sort_record.sort_part[2].field_lngth = 0
- then begin curr_level:=1;
- if sort_record.sort_part[3].field_lngth = 0
- then do_nothing else begin
- id1_is_missing:=true;
- write_header(sort_record.print[1].field_lngth,
- sort_record.print[1].field_level);
- id1_is_missing:=false;
- curr_level:=3;end;end
- else begin curr_level:=1;
- id1_is_missing:=true;
- write_header(sort_record.print[1].field_lngth,
- sort_record.print[1].field_level);
- id1_is_missing:=false;
- id2_missing_check;
- end
-
- @ This is a little macro used to access {\it write\_header}.
-
- @d write_prev_header==
- begin case curr_level of
- 1: write_header(prev_ln1,prev_pn1);
- 2: write_header(prev_ln2,prev_pn2);
- 3: write_header(prev_ln3,prev_pn3);
- othercases do_nothing
- endcases
- end;
-
- @ The function ccat will concatenate two strings together.
-
- @^System dependent code@>
- @p function ccat(x,y:string_pass):string_pass;
- begin
- ccat := x ccat_temp y;
- end;
-
- @* Opening and Closing the files.
- This is all very dependent on \PASCAL.
-
- @ The {\it reset\_file} procedure is used to open all files.
- One time this is done when first entering TEXIX.
- Note that the file name is ``{\tt IX\it n}'' where ``{\it n}'' is
- 1--3. This can easily be extended to 4--8 by chaning the \bs{}index
- markup in TEXT1@@.
- The other time the open is done is when opening the sort file, after it
- has already been sorted.
- This is system dependent. The following will work for \PASCAL.
-
- @^System dependent code@>
- @p procedure reset_file(file_number:char);
- begin
- if file_number = '9' then reset(sort_file,
- 'NAME=TEXT1$$.OUTSORT.A,LRECL=1857,RECFM=V')
- else reset(ix_file,
- ccat(ccat('NAME=TEXT1$$.IX',str(file_number)),'.A'));
- end;
-
- @
- The {\it sort\_file} is opened for output to write the sort records to.
- The {\it ix\_file} is opened for output after the sort records have
- been sorted and processed again.
- This is system dependent. The following will work for \PASCAL.
-
- @^System dependent code@>
- @p procedure file_rewrite(file_number:char);
- begin
- if file_number = '9'
- then
- rewrite(sort_file,'NAME=TEXT1$$.INSORT.A,LRECL=1857,RECFM=V')
- else
- rewrite(ix_file,
- ccat(ccat('NAME=TEXT1$$.IX',str(file_number)),
- '.A,LRECL=2048,RECFM=V'));
- end;
-
- @* The Sort Record Description. The record type called
- {\it sort\_type} is the record written to the {\it sort\_file}.
- If consists of the following:
- \la{\bf Bytes}
- \la{1}
- A one byte {\it record\_type} (0={\bf bold page number};
- 2= roman page number (the default); 4=\us{underscored} \us{page}
- \us{number};
- 6={\it italic page number}; 9=blind entry).
- \la{2--5}
- The integer page number. If the page
- number is in the preface part of the document, then the page number will
- be negative.
- \la{6--9}
- Used in sorting decending. That means that -1 will be at the top.
- If the page number is plus to begin with, then this is set to zero
- for sorting, so it will be at the bottom of the list.
- \la{10-29} This is the same as page number, unless the page number is
- negative, in which case this field is a roman numeral.
- \la{30--33\lbr34--333\lbr334--337\lbr338--637\lbr638--641\lbr642--941}
- The sort field. There are three arrays in this field. Each array
- consists of a 4 byte length, followed by the {\it field\_array} which is
- the length of the sort entry or subentry.
- It is these fields which will get sorted by @^Syncsort@> Syncsort.
- If there was a {\it sort\_as}
- used for a sort entry or subentry, that value passed in the {\it sort\_as}
- is placed here.
- \vs{24pt}
- \la{942--945\lbr946--1245\lbr1246--1249\lbr
- 1250--1549\lbr1550--1553\lbr1554--1853}
- The print field.
- The description is the same as the sort field.
- This is the way the index entry will print, but not necessarily how
- it will sort.
- \vs{96pt}
-
- @ @<Global Constants@>=
- @!max_pn_alpha=20;
- @!max_pnum=9;
-
- @ @<Global Types@>=
- @!string_pass=string_type(max_lrecl);
- @!pass_pn_alpha=string_type(max_pn_alpha);
- @!pn_type=packed array[1..max_pnum] of char;
- @!pn_alpha_type=packed array[1..max_pn_alpha] of char;
- @!field_array = packed array[1..max_field] of char;
- @!field_type = packed record@|
- @!field_lngth :integer;
- @!field_level :field_array;
- end;
- @!sort_type = packed record@/
- @!record_type :char;
- @!page_number :integer;
- @!abs_page_number :integer;
- @!page_string :pn_alpha_type;
- @!sort_part :packed array[1..3] of field_type;
- @!print :packed array[1..3] of field_type;
- end;
-
- @* Subroutines. For many of the following subroutines, the following
- global variable, {\it current\_level} is needed to indicate what
- index level we are presently processing.
- 0 = the primary index; 1 = subentry 1, and
- 2 = subentry 2.
- {\it on\_a\_roll} is `true' if we have a series of consecutive page
- numbers going. `false' otherwise.
- In other places, {\it print\_style}=1 for the paragraph style; it is
- 2 for the dash style; and it is 3 for the indent style.
-
- @<Global Var...@>=
- @!curr_level :integer;
- @!on_a_roll:boolean;
-
- @ The {\it write\_header} procedure will write out the primary and
- subentry level titles from {\it sort\_record.print}.
-
- @p procedure write_header(print_length:integer;print_field:field_array);
- var i:integer;
- begin
- case curr_level of
- 1: begin
- do_write(ix_file,'\goodbreak\hp ');
- @.\bs{}leavevmode@>
- @.\bs{}goodbreak@>
- @.\bs{}hp@>
- for i:=1 to print_length do do_write(ix_file,print_field[i]);
- case print_style of
- '1':begin
- do_write(ix_file,', ');
- end;
- '2','3':begin
- if id1_is_missing or dot_leadering
- then do_lnwrite(ix_file,' ')
- else do_lnwrite(ix_file,', ');
- end;
- othercases do_nothing
- endcases; end;
- 2: begin case print_style of
- '1':do_nothing;
- '2':begin
- do_write(ix_file,'\indentsubentry',ix,'1---');
- @.\bs{}indentsubentry@>
- end;
- '3':begin
- do_write(ix_file,'\indentsubentry',ix,'1');
- end;
- othercases do_nothing
- endcases;
- for i:=1 to print_length do do_write(ix_file,print_field[i]);
- if (print_style <> '1') or id2_is_missing or dot_leadering
- then do_lnwrite(ix_file,' ')
- else do_lnwrite(ix_file,', ');
- end;
- 3: begin case print_style of
- '1':do_nothing;
- '2':begin
- do_write(ix_file,'\indentsubentry',ix,'2---');
- end;
- '3':begin
- do_write(ix_file,'\indentsubentry',ix,'2');
- end;
- othercases do_nothing
- endcases;
- for i:=1 to print_length do do_write(ix_file,print_field[i]);
- if dot_leadering
- then do_lnwrite(ix_file,' ')
- else do_lnwrite(ix_file,', ');
- end;
- othercases do_nothing
- endcases
- end;
-
- @ The {\it numeric} function will take a packed array of length
- max\_pnum and convert
- that array (which is really the page number) into an integer.
-
- @p function numeric(simple_array:pn_type):integer;
- var @!i,j_mult,pn:integer;
- begin pn := 0;
- i := max_pnum;j_mult:=1;
- repeat
- if i = 1 then if simple_array[1] = '-'
- then pn := -1 * pn
- else pn := pn + ((ord(simple_array[1])-ord('0')) * j_mult)
- else pn := pn + ((ord(simple_array[i])-ord('0')) * j_mult);
- j_mult := j_mult * 10;
- decr(i);
- until i < 1;
- numeric:=pn;
- end;
-
- @ The {\it get\_numeric}
- function will take a packed array of length max\_pn\_alpha and convert
- that array (which is really the page number) into an integer.
-
- @p function get_numeric(x_string:string_type(max_pn_alpha)):integer;
- var @!i:integer;
- begin
- readstr(x_string,i);
- get_numeric:=i;
- end;
-
- @ The {\it strvalue} function takes an integer and converts it into
- a string.
-
- @^System dependent code@>
- @p procedure strvalue(x:integer; var results:pass_pn_alpha);
- var
- temp:string_type(max_pn_alpha);
- begin
- writestr(temp,x);
- results:=ltrim(temp);
- end;
-
- @ The {\it strconv} function takes an array and converts it into
- a string.
-
- @p function strconv(x:pn_alpha_type):string_type(max_pn_alpha);
- var i:integer;
- temp:string_type(max_pn_alpha);
- begin
- temp:='';i := 1;
- with sort_record do begin
- repeat
- if x[i] <> ' ' then
- temp := ccat(temp,str(x[i]));
- incr(i);
- until (i > max_pn_alpha) or (x[i] = ' ');
- end;
- strconv:=temp;
- end;
-
- @ The procedure {\it write\_print\_chars} will write the number of
- characters indicated
- in the parm field to the appropriate print field. There are three levels of
- print fields. Level 0 is the primary index, level 1 is the subentry 1 index,
- and level 2 is the subentry 2 index. After writing the number of characters
- to the print field, that number of characters is removed from the input record.
- You might notice that this procedure is very similar to the
- write\_sort\_chars
- procedure. The only difference in the two is that this procedure deals
- with how the index is
- to be printed after sorting. The former deals with how the
- index is to be sorted.
- Also, this procedure is called by {\it write\_sort\_chars}.
-
- @^System dependent code@>
- @p procedure write_print_chars(number_of_characters:integer);
- var m:integer;
- begin with sort_record.print[curr_level+1] do
- for m := 1 to number_of_characters do begin
- incr(field_lngth);
- field_level[field_lngth] := in_record[m];
- end;
- remove_characters(number_of_characters);
- end;
-
- @ The procedure {\it write\_sort\_chars}
- will write the number of characters indicated
- in the parm field to the appropriate sort field. There are three levels of
- sort fields. Level 0 is the primary index, level 1 is the subentry 1 index,
- and level 2 is the subentry 2 index. After writing the characters to
- the sort fields, they will be removed from the input string.
-
- @^System dependent code@>
- @p procedure write_sort_chars(number_of_characters:integer);
- var m:integer;
- begin with sort_record.sort_part[curr_level+1] do
- for m := 1 to number_of_characters do begin
- incr(field_lngth);
- field_level[field_lngth] := in_record[m];
- end;
- remove_characters(number_of_characters);
- end;
-
- @
- This procedure processes subentries within the \bs{}index command. For example,
- the phrase ``Mt. St. Helens'' would be processed here for the entry created
- by the markup:
- \vs{12pt}
- {\lin{.5in}
- {\tt\bs{}index\{volcanos\bs{}subentry1\{Mt. St. Helens\}\}}\par}
- \vs{12pt}
- \nin Note
- that there are two levels of subentries, \bs{}subentry1 and \bs{}subentry2.
- You can
- use \bs{}sortas within a \bs{}subentry. But you cannot use \bs{}subentry2 within
- \bs{}subentry1 and vise versa. If you think it should be permitted, don't.
- Also, \bs{}blindentry is not permitted within \bs{}subentry.
- (I can't be flexible {\bf everywhere}.)
-
- @ First save the current level, then set the current level to the
- subentry level. Process until the subentry is completely digested.
-
- @^System dependent code@>
- @p procedure process_subentry(@!entry_level:integer);
- var temp_level :integer;
- digest :boolean;
- begin remove_characters(1);{Throw away the `1' or `2'}@/
- temp_level := curr_level;
- curr_level := entry_level;
- digest := true;
- repeat
- @<Digest Subentry@>
- until not digest;
- curr_level := temp_level;
- end;
-
- @ If the next character is a dollar sign, then we {\bf might} have a \bs{}sortas
- If the next character is a left curly brace, then check to see if we've
- reached the end of this subentry. If the character is not `\$' or `\{',
- then write the character to the print file.
-
- @<Digest Subentry@>=
- if in_record[1] = '$'
- then @<Check for Sortas@>
- else if in_record[1] = '{'
- then @<Check for Subentry End@>
- else write_print_chars(1);
-
- @ If the next two characters are `\$\}' then we are are the end of
- the subentry.
-
- @<Check for Subentry End@>=
- begin
- if (in_record[2] = '$') and (in_record[3] = '}')
- then begin
- digest := false;
- remove_characters(3);
- end
- else write_print_chars(1);
- end
-
- @ If the next three are `\{\$\}' then we {\it might} have a sortas.
- and check the next two
- characters to see if they
- are `{\tt sa}'. If so, we {\bf do} have a sortas.
- Otherwise write those 6 characters out. In any case, if we don't have
- a `\{\$\}' to begin with, then write the first character out
- (which was a
- `\$' if you remember from earlier.)
-
- @<Check for Sortas@>=
- if (in_record[2] = '{') and
- (in_record[3] = '$') and (in_record[4] = '}')
- then begin
- if (in_record[5] = 's') and (in_record[6] = 'a')
- then do_sort_as
- else write_print_chars(6);
- end
- else write_print_chars(1)
-
- @
- The {\it equal\_arrays}
- function returns a true if the two arrays being passed are
- identical. False if not.
-
- @p function equal_arrays(fieldy:field_array;fieldz:field_array):boolean;
- var i :integer;
- still_checking :boolean;
- begin i := 1;
- still_checking := true;
- repeat
- if fieldy[i] <> fieldz[i] {if arrays not equal}
- then still_checking := false
- else incr(i);
- until (i>max_field) or not still_checking;
- equal_arrays := still_checking;
- end;
-
- @ The {\it plsort} procedure is written in PL/1 to call the CMS sort program
- Syncsort. This was necessary since you cannot call Syncsort from PASCAL/VS.
- The fields to be sorted are defined internally in the {\it plsort}
- program. This should be the same as the three sort fields in {\it sort\_type}.
- @:sort_type@>
- @:plsort@> @^PL/1@>
- @^Syncsort@>
-
- @p procedure plsort(var sort_rc:integer); fortran;
-
- @ This function converts to all uppercase.
- Notice that this is an EBCIDIC conversion, not an ASCII conversion
- to uppercase.
-
- @p function upper_case(x:char):char;
- var temp:char;
- begin
- if (ord(x)>=129)and(ord(x)<=169) then
- temp:=chr(ord(x)+64)
- else temp:=x;
- upper_case:=temp;
- end;
-
-
- @* Read Each Index Entry.
- Each line in the {\it ix\_file} is a separate index entry generated with the
- \bs{\it index markup}. This markup has the format
- \par{\tt\bs{}index\it n\tt\{\it entry\rm/\it markup\tt\}}
- \par
- \nin where ``{\it entry}''
- is the textual material of the primary index. The
- ``{\it markup}'' may be one of the following submarkup
- which may {\bf only}
- appear within the \bs{\it index markup}. Never outside of it.
- \item{1.} {\tt\bs{}subentry{\it n\/}}: where {\it n} is ``1'' or ``2'',
- denoting the subentry level.
- You would use this submarkup in the following fashion:
- \par{\lin{+.5in}\tt\bs{}index1\{\rm entry
- \bs\rm subentry1\tt\{\it submarkup\tt\}\}\par}
- \indent where {\it submarkup} here can only be \bs{\it sortas}.
- \item{2.}{\tt\bs{}sortas}: This markup is used to indicate text for either the
- primary sort level, or one of the two subentry sort levels that is to be
- sorted, but not printed in the resulting index. For example, someone may
- want ``10 Downing Street''
- to sort as ``ten Downing Street''. This would be accomplished by entering
- ``{\tt\bs{}index1\{10 Downing Street\bs{}sortas\{ten Downing Street\}\}}''.
- You can also use \bs{\it sortas} within the \bs{\it subentry} submarkup.
- \item{3.}
- {\tt\bs{}itpn}: This markup indicates this index number
- is to be printed in italics in the sorted index.
- To use it, enter:
- \par{\lin{+.5in}\tt\bs{}index1\{\rm entry \tt
- \bs{}itpn\}\par}
- \item{4.} {\tt\bs{}bdpn}: This markup indicates this
- index number is to be
- printed in bold in the sorted index.
- To use it, enter:
- \par{\lin{+.5in}\tt\bs{}index1\{\rm entry \tt
- \bs{}bdpn\}\par}
- \item{5.} {\tt\bs{}uspn}: This markup indicates
- this index number is to
- be underscored in the sorted index.
- To use it, enter:
- \par{\lin{+.5in}\tt\bs{}index1\{\rm entry \tt
- \bs{}uspn\}\par}
- \item{6.} {\tt\bs{}blindentry}: This markup indicates this index is to be
- a blind entry or ``cross reference''. It may appear inside of a
- standard entry or subentry. There is no page number associated with
- this submarkup.
- \par
-
- @ @<Global Var...@>=
- @!respect_case :boolean;
- @!dot_leadering :boolean;
- @!print_style:char;
- @!sort_record :sort_type;
- @!in_record :string_type(max_lrecl);
- @!temp_strvalue:pass_pn_alpha;
-
- @^System dependent code@>
- @ This procedure will read the {\it ix\_file} in until all index requests
- have been read.
-
- @p procedure read_all_entries;
- var @!i,j,k:integer;
- begin
- @<Get Default Index Values@>
- while not eof(ix_file) do begin
- @<Initialize Sort Records@>@/
- @<Read Next Record@>@/
- @<Move Sort Type to Sort Record@>@/
- @<Move Page Number to Sort Record@>@/
- @<Digest the Input Record@>@/
- @<Fill in Sort Fields@>@/
- @<Write Sort Record@>@/
- end;end;
-
- @ The first index default variable passed is ``case=". A ``yes" value will
- respect the case in an index sort field. ``no" (the default) will convert
- everything to uppercase before sorting.
-
- The second index default ``style=" will be one of ``1", ``2'', or ``3''
- depending on whether the style is ``paragraph'', ``dash'', or ``indented''
- (which is the default).
-
- The third default read in here is the ``leadering=". A ``yes'' here will give
- dot leadering. Guess what ``no'' does.
- Dot leadering in the paragraph style ({\it print\_style}=1). If that
- has been requested, change {\it dot\_leadering} to false.
-
- @<Get Default Index Values@>=
- readln(ix_file,in_record);
- if dosubstr(in_record,doindex(in_record,'=')+1) = 'no'
- then respect_case := false
- else respect_case := true;
- readln(ix_file,in_record);@/
- print_style:=in_record[doindex(in_record,'=')+1];@/
- readln(ix_file,in_record);@/
- if dosubstr(in_record,doindex(in_record,'=')+1) = 'no'
- then dot_leadering := false
- else dot_leadering := true;@/
- if dot_leadering and (print_style = '1')
- then begin writeln(messages,
- '<TEXT1> Error! Dot leadering not permitted with the paragraph style.');
- writeln(messages,' Dot leadering will be disabled.');
- dot_leadering := false;
- end;
-
- @ The {\it all\_blanks} variable is filled with all blanks. Other arrays
- of the same dimension of {\it all\_blanks} can be set to blank themselves
- by saying $array\leftarrow all\_blanks$.
-
- @<Global Var...@>=
- @!all_blanks:field_array;
-
- @ @<Initialize Sort Records@>=
- with sort_record do
- for i := 1 to max_levels do begin
- sort_part[i].field_level:= all_blanks;
- sort_part[i].field_lngth := 0;
- print[i].field_level:= all_blanks;
- print[i].field_lngth := 0;
- end;
- curr_level := 0;
-
- @ Read the next index request to be processed.
- Get rid of trailing blanks.
-
- @<Read Next Record@>=
- readln(ix_file,in_record);
- in_record:=trim(in_record);
-
- @ The {\it sort\_type} is always in column 2. Column 1, 3 and 4 will always
- be curly braces. (`\{{\it s}\}\{' where ``{\it s}'' is the sort type.)
- After moving the {\it sort\_type} to the sort record, then
- delete the {\it sort\_type} and the three curly braces.
-
- @<Move Sort Type to Sort Record@>=
- sort_record.record_type := in_record[2];
- remove_characters(4);
-
- @ The end of the page number is the next right curly brace (`\}').
- Move all of the digits from the input record to the sort record,
- starting with the last digit and going forward. If a minus sign (`-')
- is in
- the page number (preface material), then put a minus sign in
- byte one of the sort record's page number.
-
- @<Global Var...@>=
- @!in_page_number:pn_type;
-
- @ Find and move the page number to the sort record. If it is negative,
- then its a roman numeral. In that case, move the page number to the
- {\it abs\_page\_number} to be sorted descending, as negative numbers
- should be. If its not negative, then move zero to {\it abs\_page\_number}
- so it will move to the bottom of that sort field.
- After it is moved, delete the appropriate number of characters to
- finish digesting the entry.
-
- @<Move Page Number to Sort Record@>=
- k := doindex(in_record,'}'); {find the end of the page number}
- i := k - 1;
- for j := 1 to max_pnum do in_page_number[j] := '0';
- j := max_pnum;
- repeat
- if in_record[i] = '-'
- then begin
- in_page_number[1] := '-';
- i := 0;
- end
- else begin
- in_page_number[j] := in_record[i];
- decr(i);
- decr(j);
- end;
- until i <= 0;
- remove_characters(k+1);@/
- sort_record.page_number:=numeric(in_page_number);@/
- if sort_record.page_number < 0
- then sort_record.abs_page_number:=abs(sort_record.page_number)
- else sort_record.abs_page_number:=0;
- k := doindex(in_record,'}'); {find the end of the page number string}
- for i := 1 to max_pn_alpha do sort_record.page_string[i] := ' ';
- for i := 1 to k-1 do
- sort_record.page_string[i] := in_record[i];
- remove_characters(k);
-
- @^System dependent code@>
- @ Process the rest of the input record. Each time you see a dollar sign,
- there could be a submarkup coming, so examine the next three characters.
-
- @<Digest the Input Record@>=
- repeat
- if (in_record[1] = '$') and (length(in_record) >= 4)
- then @<Examine Next 3 Chars@>
- else write_print_chars(1);
- until length(in_record) < 1;
-
- @ Once the index request has been digested, each sort field is checked
- to see if it is blank. If so, then {\it sort\_as} was not used, so copy the
- {\it print} field to the {\it sort} field.
-
- @<Fill in Sort Fields@>=
- with sort_record do begin
- for i := 1 to max_levels do
- if sort_part[i].field_lngth=0
- then begin
- sort_part[i].field_level := print[i].field_level;
- sort_part[i].field_lngth := print[i].field_lngth;
- check_case; end
- else check_case;
- end;
-
- @^System dependent code@>
- @ Ok, the record has been processed, so write it to the output file.
-
- @<Write Sort Record@>=
- sort_file@@:=sort_record;
- put(sort_file);
-
- @ Ok, a dollar sign signals the beginning of some sort of action code if the
- next three characters are `\{\$\}'. So lets look at them and see.
-
- @<Examine Next 3 Chars@>=
- begin if (in_record[2] = '{') and
- (in_record[3] = '$') and (in_record[4] = '}')
- then @<Examine Next 2 Chars@>
- else write_print_chars(1);{Well then, the dollar sign must be part of the index}
- end
-
- @ If a {\it blindentry} (`{\tt be}') or {\it subentry} (`{\tt se}'),
- then perform the appropriate sections.
-
- @<Examine Next 2 Chars@>=
- begin if (in_record[5] = 'b') and (in_record[6] = 'e')
- then @<Do Blind Entry@>
- else if (in_record[5] = 's') and (in_record[6] = 'e')
- then @<Do Sub Entries@>
- else if (in_record[5] = 's') and (in_record[6] = 'a')
- then do_sort_as
- else write_print_chars(6);{Might as well write all 6 characters examined}
- end
-
- @ Everything up to the next `\{\$\}' is the blind entry.
- The page number for a blind entry will always be 999999999.
-
- @<Do Blind Entry@>=
- begin remove_characters(6);{Throw away the `\$\{\$\}be'}@/
- i := doindex(in_record,'{$}');
- curr_level:=2;
- write_print_chars(i-1);
- curr_level:=0;
- remove_characters(3);{Throw away the `\{\$\}'}
- sort_record.page_number := 999999999;
- end
-
- @ Process the subentry, depending on whether or not it is
- {\it subentry}1 or {\it subentry}2. If not, ignore the whole thing.
-
- @<Do Sub Entries@>=
- begin remove_characters(6); {Throw away the `\$\{\$\}se'}
- if in_record[1] = '1'
- then process_subentry(1)
- else if in_record[1] = '2'
- then process_subentry(2)
- else write_print_chars(1);{Perhaps someone entered \bs{}subentry3??}
- end
-
- @* Write Formated Index. This section of code takes the sorted index
- entries, merges them together, and writes them back out to the index file
- to be read in by \bs{}printindex in the user's program. This section consists
- of three procedures for accomplishing this feat: {\it add\_page\_number},
- {\it digest\_the\_line}, and {\it read\_sorted\_records}.
- {\it numeric} is a function to convert the character string page number into
- an integer.
-
- @^System dependent code@>
- @ The procedure {\it add\_page\_number} is used to add the page number of the
- current sorted record to the {\it string\_bold} if a
- \bs{\it bdpn}, or to
- the {\it string\_underscore} if a \bs{\it uspn},
- or otherwise to
- the {\it str\_build}.
-
- @p procedure add_page_number;
- var i:integer;
-
- @ @<Global Var...@>=
- @!prev_page_number:integer;
- @!prev_pg_string:string_type(max_pn_alpha);
- @!prev_record_type:char;
-
- @ First check to see if we have a new page number. If so, then add the page
- number to the string. Otherwise, only add the page number if the sort type
- is new and is not equal to ``6'' (italic).
-
- @p
- begin
- with sort_record do if prev_page_number = page_number
- then if (prev_record_type = record_type) and (record_type <> '9')
- then getout
- else if record_type = '6' then getout;
- @<Add Page Number to the String@>
- end;
-
- @ {\it str\_build} is used to accumulate all of the page numbers.
- {\it str\_blind\_entry} is used to accumulate the blind entry information
- (typically there should be no more than one, but allowance is made for more.)
-
- @<Global Var...@>=
- @!str_build:string_type(max_lrecl);
- @!str_blind_entry:string_type(max_lrecl);
- {come on, who's going to have one that long?}
-
- @ This module will take the page number of the current sorted index
- record and add it to the build string, unless the record type is
- 9, which is a blind entry, in which case it is added to the blind entry
- string. Note that if the record type is 0 (bold), 4 (underscore) or
- 6 (italic), then the page number is prefaced with ``B'', ``U'' or
- ``I'' respectively. This identifies that the page number is to be
- emphasized when the build string is processed through the
- {\it digest\_the\_line} procedure.
-
- @<Add Page Number to the String@>=
- if sort_record.record_type = '9' then @<Do Sorted Blind Entry@>
- else begin @<Do Sorted Non Blind Entry@>
- end;
- prev_page_number := sort_record.page_number;@/
- prev_pg_string := strconv(sort_record.page_string);@/
- prev_record_type := sort_record.record_type;
-
- @ @<Do Sorted Blind Entry@>=
- with sort_record.print[3] do begin
- if length(str_blind_entry) > 0 then add_cmma_blnk(str_blind_entry);
- for i := 1 to field_lngth do
- str_blind_entry := ccat(str_blind_entry,str(field_level[i]));
- end
-
- @ If the {\it page\_string[1]} is less than zero, its alphabetic and
- roman numeral processing is necessary.
-
- @<Do Sorted Non Blind Entry@>=
- with sort_record do begin
- if ord(page_string[1]) < ord('0')
- then @<Add Roman Page Number@>
- else @<Add Arabic Page Number@>;
- end;
-
- @ @<Add Roman Page Number@>=
- begin
- if length(str_build) >= 1
- then str_build:=ccat(',',str_build);
- strvalue(page_number,temp_strvalue);
- str_build := ccat(ccat(ccat(strconv(page_string),
- ','),temp_strvalue),str_build);
- if record_type = '0'
- then str_build := ccat('B',str_build)
- else if record_type = '4'
- then str_build := ccat('U',str_build)
- else if record_type = '6'
- then str_build := ccat('I',str_build)
- end
-
- @ @<Add Arabic Page Number@>=
- begin
- if length(str_build) >= 1
- then add_comma(str_build);
- if record_type = '0'
- then str_build := ccat(str_build,'B')
- else if record_type = '4'
- then str_build := ccat(str_build,'U')
- else if record_type = '6'
- then str_build := ccat(str_build,'I');
- str_build := ccat(str_build,strconv(page_string));
- end
-
- @ {\it output\_string} is used to collect all of the page numbers
- before writing them back out to the index file;
- {\it bold\_string} collects the bold page numbers;
- {\it us\_string} collects the underscored page numbers;
- {\it rm\_string} collects everything not bold or underscored.
- As you might expect, {\it italic\_last\_page} is true when the last
- page number of a `roll' is to be italic.
-
- @<Global Var...@>=
- @!output_string:string_type(max_lrecl);
- @!bold_string:string_type(max_lrecl);
- @!us_string:string_type(max_lrecl);
- @!rm_string:string_type(max_lrecl);
- @!italic_last_page:boolean;
-
- @^System dependent code@>
- @ {\it finish\_the\_process} is a procedure that is used to
- first check to see if we are {\it on\_a\_roll}, which means we are formatting
- something like pages 1-3.
- After doing that, if there were any bold page numbers, they are concatenated
- to the front of the {\it output\_string}; underscored page numbers (if any)
- are concatenated to the end of the {\it output\_string}.
-
- @p procedure finish_the_process;
- begin
- @<Concatenate Bold Pages to Output@>;@/
- @<Concatenate Roman Pages to Output@>;@/
- @<Concatenate Underscored Pages to Output@>;
- end;
-
- @ If there were any bold page numbers, then add them to the {\it
- output\_string}.
-
- @<Concatenate Bold...@>=
- if length(bold_string) > 0 then begin
- if length(output_string) > 0 then add_cmma_blnk(output_string);
- output_string := ccat(output_string,bold_string);
- end
-
- @ If we were on a roll (a consecutive series of page numbers) then finish
- the roll. Then if there were any roman or italic page numbers, add them to
- the {\it output\_string}.
-
- @<Concatenate Roman...@>=
- if on_a_roll then if italic_last_page
- then rm_string :=
- ccat(ccat(ccat(rm_string,'{\it '),trim(prev_pg_string)),'}')
- else rm_string := ccat(rm_string,prev_pg_string);
- @.\bs{}it@>
- if length(rm_string) > 0 then begin if length(output_string) > 0
- then add_cmma_blnk(output_string);
- output_string := ccat(output_string,rm_string);
- end
-
- @ If there were any underscored page numbers, add them to the {\it
- output\_string} here.
-
- @<Concatenate Under...@>=
- if length(us_string) > 0 then begin if length(output_string) > 0
- then add_cmma_blnk(output_string);
- output_string := ccat(output_string,us_string);
- end
-
- @ The procedure {\it start\_digesting} will initialize a few variables,
- then add the {\it current\_page} to the appropriate list.
-
- @p procedure start_digesting;
- begin @<Initialize Some Global Variables@>;@/
- prev_pg_string := curr_str_page;@/
- @<Do Appropriate Highlighting@>;
- end;
-
- @ @<Initialize Some Global Variables@>=
- italic_last_page := false;
- bold_string := ''; us_string :=''; rm_string:='';
- starting_to_process:=false;
- on_a_roll:=false
-
- @ @<Get the Current Print Type of this Page Number@>=
- print_type:= curr_str_page[1];
- if (print_type='B') or (print_type='I') or (print_type='U')
- then curr_str_page:=dosubstr(curr_str_page,2)
- else print_type := ' '
-
- @ @<Do Appropriate Highlighting@>=
- if print_type = 'B' then do_when_bold
- else if print_type = 'I' then do_when_italic
- else if print_type = 'U' then do_when_underscore
- else do_when_roman
-
- @^System dependent code@>
- @ The procedure {\it digest\_the\_line} will take the full {\it str\_build}
- and add the dashes when there is a run of page numbers (i.e. ``{\tt 1,2,3}'' bec
- ``1-3''); add the bold page numbers in front of the string (i.e.
- ``{\tt 1,2,B3,3,4}''
- prints as ``{\bf 3},1-4''. Note that page 3 had to appear twice
- ``{\tt B3,3}''. If it had only appeard as a bold page number and not the
- default, ``{\tt 1,2,B3,4}'', you would get ``1-2,{\bf 3},4'');
- add the underscored
- page numbers to the end of the string (similar to bold page numbers,
- ``1,2,U3,3,4'' prints as ``1-4,\us{3}''); and print in italics when
- necessary.
-
- @p procedure digest_the_line;
- var
- i:integer;
- @!temp_roman:string_type(max_pn_alpha);
- @!no_page_numbers:boolean;
- begin
- @<Process Each Page Number@>;@/
- @<Write the Line Out@>;
- end;
-
- @ @<Global Var...@>=
- @!starting_to_process :boolean;
- @!print_type:char;
- @!curr_str_page :string_type(max_pn_alpha);
- @!curr_num_page :integer;
-
- @ Initialize the variables, then read each page number until the whole
- string is digested, then finish off the page number string before returning.
- If {\it str\_build} is null, then we are doing a blind entry with no
- page numbers associated. In that case, initialize the highlighting
- strings.
- @<Process Each Page Number@>=
- output_string := '';
- starting_to_process := true;
- no_page_numbers:=false;
- if length(str_build) > 0
- then repeat @<Digesting Each Page Number@>
- until length(str_build) < 1
- else if starting_to_process then begin
- @<Initialize Some Global Variables@>;
- no_page_numbers:=true;
- end;
- finish_the_process;
-
- @ First get the next page number. Then if we are starting, initialize
- everything. If we have already started, then check to see if we have a
- consecutive page number sequence (i.e. pages 1,2,3,4 etc.) which is called
- a `roll'.
- @<Digesting Each Page Number@>=
- @<Get Next Page Number@>;@/
- if starting_to_process
- then start_digesting
- else @<Check for a Roll@>;
- prev_page_number:=curr_num_page;
-
- @ @<Get Next Page Number@>=
- i := doindex(str_build,',');
- if i < 1 then begin curr_str_page:=str_build; str_build:='';end
- else begin
- curr_str_page:=dosubstr(str_build,1,i-1);
- str_build := dosubstr(str_build,i+1);
- end;
- @<Get the Current Print Type of this Page Number@>;@/
- if ord(curr_str_page[1]) < ord('0') {Then its alphabetic}
- then @<Get Numeric for Roman Page Number@>
- else curr_num_page:=get_numeric(curr_str_page);
-
- @ @<Get Numeric for Roman Page Number@>=
- begin
- i := doindex(str_build,',');
- if i < 1 then begin temp_roman:=str_build; str_build:='';end
- else begin
- temp_roman:=dosubstr(str_build,1,i-1);
- str_build := dosubstr(str_build,i+1);
- end;
- curr_num_page:=get_numeric(temp_roman);
- end
-
- @ If we are on a roll, then the previous page number will be one less than
- the current page number. If this is not the case, then {\it
- finish\_the\_process}
- and {\it start\_digesting} all over again.
-
- @<Check for a Roll@>=
- if ((prev_page_number = curr_num_page) and (print_type <> ' ')) or
- ((prev_page_number>=0) and (prev_page_number = curr_num_page - 1)) or
- ((prev_page_number<0) and (prev_page_number = curr_num_page + 1))
- then begin
- @<Got a Roll Going@>
- prev_pg_string:=curr_str_page;
- end
- else begin finish_the_process; start_digesting; end
-
- @ Ok, so we're on a roll, right? If the {\it print\_type} is ``B'' (bold) or
- ``U'' (underscored) then do those and return. Otherwise, check to se if we
- were previously {\it on\_a\_roll}. If we weren't, then add the hyphen to the
- starting page number. In either case, move the {\it current\_page} to the
- {\it prev\_pg\_string}. Lastly, if the page number is italic, then set
- {\it italic\_last\_page} to true, in case it ends up being the last page in
- the string.
-
- @<Got a Roll Going@>=
- if print_type = 'B' then do_when_bold
- else if print_type = 'U' then do_when_underscore
- else begin if not on_a_roll then begin on_a_roll := true;
- rm_string:=ccat(rm_string,'--'); end;
- if print_type = 'I' then italic_last_page := true
- else italic_last_page := false;
- end;
-
- @ Before the page numbers are actually written, we need to write out
- the ID depending on which level we are formatting. Level 1 is the
- primary level, level 2 is the subentry1, and level 3 is subentry2.
- Then, we need to do a couple of things depending on whether there is
- dot leadering going on or not.
- Finally, write the output string to the formatted index file.
-
- @<Write the Line Out@>=
- write_prev_header;
- if dot_leadering then begin @<Do Dot Leadering@> end
- else begin @<Do not do Dot Leadering@> end;
- do_lnwrite(ix_file,output_string);
-
- @ If there is dot leadering, then add the blind entry first, before adding
- the leadering.
-
- @<Do Dot Leadering@>=
- if length(str_blind_entry) > 0
- then begin
- if length(output_string) > 0 then add_cmma_blnk(output_string);
- output_string := ccat(output_string,str_blind_entry);
- end;
- output_string := ccat(ccat('\leader{}',output_string),'\par');
- @.\bs{}leader@>
- @.\bs{}par@>
-
- @ @<Global Var...@>=
- @!new_level_1:boolean;
-
- @ If there is not dot leadering, then the blind entry goes at the end of the
- page, except for
- the paragraph style ({\it print\_style}=1). Also, if the paragraph style,
- then do not add the {\tt \bs{}par} at the end. Instead, add a comma
- if there is a new level 1 entry.
-
- @<Do not do Dot Leadering@>=
- if (print_style <> '1') and (length(str_blind_entry) > 0)@/
- then begin
- if length(output_string) > 0 then add_cmma_blnk(output_string);
- output_string := ccat(output_string,str_blind_entry);
- end;
- if print_style = '1'
- then if new_level_1 and ((length(str_blind_entry)=0) or no_page_numbers)
- then do_nothing
- else add_cmma_blnk(output_string)
- else output_string := ccat(output_string,'\par');
- @.\bs{}par@>
-
- @ The {\it build\_sorted\_index} procedure is the driving force behind
- formatting the index. The basic process is to read all of the sorted records in
- and create a record called {\it str\_build}. There will be one of these for
- each primary and subentry level index. After doing the {\it str\_build},
- this record is then read through again to add the {\it\TeX T1} markup
- necessary to
- print out the sorted index line.
-
- @p procedure build_sorted_index;
- var @!first_time_through:boolean;
-
- @ @<Global Var...@>=
- @!prev_sr1:field_array;
- @!prev_sr2:field_array;
- @!prev_sr3:field_array;
- @!prev_pn1:field_array;
- @!prev_ln1:integer;{the length of pn1}
- @!prev_pn2:field_array;
- @!prev_ln2:integer;{the length of pn2}
- @!prev_pn3:field_array;
- @!prev_ln3:integer;{the length of pn3}
- @!id1_is_missing:boolean;
- @!id2_is_missing:boolean;
-
- @ The first thing we need to do is read the next sorted record. If this is the
- first time ever through this procedure, then do some quick initializing. Then,
- once we come to a new ID, we should write out the previous index page numbers,
- etc. If the ID has not changed from the previous record, then add the page
- number given here on the sorted record to the {\it str\_build}.
-
- @p begin first_time_through:=true;
- while not eof(sort_file) do begin
- sort_record:=sort_file@@;
- get(sort_file);
- if first_time_through then begin @<Do First Time Inits@> end;
- if not equal_arrays(prev_sr1,sort_record.sort_part[1].field_level)
- then begin
- @<Start a New Level 1@> end
- else if not equal_arrays(prev_sr2,sort_record.sort_part[2].field_level)
- then begin
- @<Start a New Level 2@> end
- else if not equal_arrays(prev_sr3,sort_record.sort_part[3].field_level)
- and (sort_record.record_type <> '9')
- then begin
- @<Start a New Level 3@> end
- else add_page_number;
- end;
- @<Digest and Print Level 1@>
- end;
-
- @ First write out the {\it \bs{}everyindex} record at the beginning
- of the index file.
-
- @<Do First Time Inits@>=
- do_lnwrite(ix_file,'\everyindex{',ix,'}');
- @.\bs{}everyindex@>
-
- @ These initializations only get done at the beginning of the
- first sort record.
-
- @<Do First Time Inits@>=
- first_time_through:=false;
- id1_is_missing:=false;
- id2_is_missing:=false;
- new_level_1:=false;
- with sort_record do begin
- prev_sr1:=sort_part[1].field_level;
- prev_sr2:=sort_part[2].field_level;
- prev_sr3:=sort_part[3].field_level;
- prev_pn1:=print[1].field_level;
- prev_ln1:=print[1].field_lngth;
- prev_pn2:=print[2].field_level;
- prev_ln2:=print[2].field_lngth;
- prev_pn3:=print[3].field_level;
- prev_ln3:=print[3].field_lngth;
- end;
- prev_page_number:=0;
- str_blind_entry:='';@/
- str_build:='';@/
-
- @ If this is not a blind entry, then check to see if sort records for
- the first level id are missing. If they are, then the id name itself
- will be printed in {\it id1\_missing\_check}.
-
- @<Do First Time Inits@>=
- if sort_record.record_type <> '9'
- then id1_missing_check;
-
- @ Only alpha (a--z and A--Z) and numeric (0--9) characters get an
- {\it \bs{}everyletterbreak}. Punctuation, for example, will not get
- an {\it \bs{}everyletterbreak}.
-
- @<Do First Time Inits@>=
- with sort_record.sort_part[1] do begin
- if ((field_level[1]>='a') and (field_level[1]<='i')) or @/
- ((field_level[1]>='j') and (field_level[1]<='r')) or @/
- ((field_level[1]>='s') and (field_level[1]<='z')) or @/
- ((field_level[1]>='A') and (field_level[1]<='I')) or @/
- ((field_level[1]>='J') and (field_level[1]<='R')) or @/
- ((field_level[1]>='S') and (field_level[1]<='Z')) or @/
- ((field_level[1]>='0') and (field_level[1]<='9'))
- then
- do_lnwrite(ix_file,'\everyletterbreak{',ix,'}{',field_level[1],'}')
- else
- do_lnwrite(ix_file,'\everyletterbreak{',ix,'}{}');
- end
- @.\bs{}everyletterbreak@>
-
- @
- First we need to {\it digest\_the\_line} which is the current index's
- entry. {\it digest\_the\_line} will write out the formatted index unless
- we are in the paragraph
- style of formatted index
- ({\it print\_style}=1). If we are in the paragraph style,
- then we need to write out any {\it str\_blind\_entry} pending.
-
- @<Digest and Print Level 1@>=
- new_level_1:=true;
- digest_the_line;
- if print_style = '1' then
- do_lnwrite(ix_file,str_blind_entry,'\par');
- new_level_1:=false;
- @.\bs{}par@>
-
- @ We have just found the start of a new primary index level.
- First we need to process the previous index's
- entry.
- If there is a blind entry, and it is style `1', then add it now.
- Next, if we are at a letter break (i.e., going from the sorted ``A''
- primary index letters to the ``B''s) then write the ``{\tt
- \bs{}everyletterbreak}'' to the formatted index file.
-
- @<Start a New Level 1@>=
- @<Digest and Print Level 1@>
- with sort_record.sort_part[1] do begin
- if (field_level[1] <> prev_sr1[1])
- then if
- (((field_level[1]>='a') and (field_level[1]<='i')) or @/
- ((field_level[1]>='j') and (field_level[1]<='r')) or @/
- ((field_level[1]>='s') and (field_level[1]<='z')) or @/
- ((field_level[1]>='A') and (field_level[1]<='I')) or @/
- ((field_level[1]>='J') and (field_level[1]<='R')) or @/
- ((field_level[1]>='S') and (field_level[1]<='Z')) or @/
- ((field_level[1]>='0') and (field_level[1]<='9'))) @/
- then do_lnwrite(ix_file,'\everyletterbreak{',ix,'}{',field_level[1],'}')
- else
- do_lnwrite(ix_file,'\everyletterbreak{',ix,'}{}');
- end;
- @.\bs{}everyletterbreak@>
-
- @ The next thing to be done when starting a new primary index is to
- check the subentries. If they exist, then you can assume that this
- primary level index has no page numbers associated with it. The macro
- {\it id1\_missing\_check} accomplishes this.
-
- @<Start a New Level 1@>=
- curr_level:=1;@/
- if sort_record.record_type <> '9'
- then id1_missing_check;
-
- @ The complicated stuff is done. So now we can actually do some simple
- initializations to get this new level 1 (primary level) sort rolling.
-
- @<Start a New Level 1@>=
- str_build:='';
- str_blind_entry:='';
- with sort_record do begin
- prev_sr1:=sort_part[1].field_level;
- prev_sr2:=sort_part[2].field_level;
- prev_sr3:=sort_part[3].field_level;
- prev_pn1:=print[1].field_level;
- prev_ln1:=print[1].field_lngth;
- prev_pn2:=print[2].field_level;
- prev_ln2:=print[2].field_lngth;
- prev_pn3:=print[3].field_level;
- prev_ln3:=print[3].field_lngth;
- prev_page_number:=0;
- end;
- add_page_number;
-
- @ We have just found the start of a new subentry1 index level.
- These modules are similar to {\it Start a New Level 1}, but not as
- detailed since it is dealing with fewer levels.
- First we need to {\it digest\_the\_line} which is the previous index's
- entry. {\it digest\_the\_line} will write out the formatted index unless
- we are in the paragraph
- style of formatted index
- ({\it print\_style}=1).
-
- @<Start a New Level 2@>=
- digest_the_line;
-
- @ The next thing to be done when starting a new subentry1 index is to
- check the subentry2. If it exists, then you can assume that this
- subentry index has no page numbers associated with it.
- This is done in {\it id2\_missing\_check}.
-
- @<Start a New Level 2@>=
- id2_missing_check;
-
- @ The complicated stuff is done. So now we can actually do some simple
- initializations to get this new level 2 (subentry2 level) sort rolling.
-
- @<Start a New Level 2@>=
- str_build:='';
- if print_style <> '1' then str_blind_entry:='';
- with sort_record do begin
- prev_sr2:=sort_part[2].field_level;
- prev_sr3:=sort_part[3].field_level;
- prev_pn2:=print[2].field_level;
- prev_ln2:=print[2].field_lngth;
- prev_pn3:=print[3].field_level;
- prev_ln3:=print[3].field_lngth;
- prev_page_number:=0;
- end;
- add_page_number;
-
- @ We have just found the start of a new subentry2 index level.
- These modules are similar to {\it Start a New Level 2}, but not as
- detailed since it is dealing with the lowest level.
- First we need to {\it digest\_the\_line} which is the previous index's
- entry. {\it digest\_the\_line} will write out the formatted index unless
- we are in the paragraph
- style of formatted index
- ({\it print\_style}=1).
-
- @<Start a New Level 3@>=
- digest_the_line;
- curr_level:=3;
-
- @ Do some
- initializations to get this new level 3 (subentry2) sort rolling.
-
- @<Start a New Level 3@>=
- str_build:='';
- if print_style <> '1' then str_blind_entry:='';
- with sort_record do begin
- prev_sr3:=sort_part[3].field_level;
- prev_pn3:=print[3].field_level;
- prev_ln3:=print[3].field_lngth;
- prev_page_number:=0;
- end;
- add_page_number;
-
- @* Main Program.
- Ok, here is the main program. First we initialize (all\_blanks); then
- set the ix\_file for input and the sort\_file for output; read all of the
- entries, processing each one; close the files; sort; read the sorted file
- in and build the entries, writing them back to the ix\_file to be read in
- by the index markup. WHEW!!
-
- @p
- begin @<Initialize Main@>@/
- termout(messages);
- reset_file(ix);@/
- file_rewrite(s_file_number); {Should always be file 9}@/
- read_all_entries;@/
- close(ix_file);@/
- close(sort_file);@/
- @<Sort the Index@>@/
- reset_file(s_file_number);@/
- file_rewrite(ix);@/
- build_sorted_index;@/
- end;
-
- @ @<Initialize Main@>=
- for i := 1 to max_field do all_blanks[i] := ' ';
-
- @ As mentioned earlier, {\it plsort} is an external PL/1 subroutine
- @^PL/1@>
- @^Syncsort@>
- which is used to call Syncsort to sort the file.
- The sort fields are as follows:
- \halign{\hskip3em\hfill#\hfill&&\hskip3em\hfill#\hfill\cr
- \bf Starting Column&\bf Length&\bf Field Description&\bf Order\cr
- 38&300&character&ascending\cr
- 342&300&character&ascending\cr
- 646&300&character&ascending\cr
- 10&4&binary&descending\cr
- 6&4&binary&ascending\cr}
-
- @<Global Var...@>=
- sort_rc:integer;
-
- @ @<Sort the Index@>=
- plsort(sort_rc);
- if sort_rc = 0
- then writeln(messages,'Index Successfully Completed')
- else writeln(messages,'Index Failed');
-
- @* Index.
- All modules in which an identifier is
- used are listed with that identifier, except that reserved words are
- indexed only when they appear in format definitions, and the appearances
- of identifiers in module names are not indexed. Underlined entries
- correspond to where the identifier was declared. Error messages, control
- sequences put into the output, and a few
- other things like ``Syncsort'' are indexed here too.
-